#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#include <signal.h>
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <mqueue.h>
// pour la shm posix
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include "init_functions.h"
#include "mise_en_carton.h"
#include "mise_en_palette.h"
#include "impression.h"
#include "stockage.h"
#include "retrait.h"
#include "ResChaineCond.h"
#include "../interface/partage_simu.h"
#include "../interface/constantes.h"
#include "../interface/messqueue.h"
#include "../interface/mutexpartage.h"
#include "../interface/variablesglobales.h"
#include "../utils/utils.h"

void set_values();
void init_shm();
void init_sem();
void launch_threads();
void init_boite_au_lettres();

static mqd_t bal_carton;
static mqd_t bal_palettes;
static mqd_t bal_impression;

static pthread_t thread_mise_en_carton;
static pthread_t thread_impression;
static pthread_t thread_mise_en_palette;
static pthread_t thread_stockage;
static pthread_t thread_retrait;

/**
	* initialise la chaine de conditionnement
	* charge la shm, init les boites au lettres
	* lance les threads de la chaine de conditionnement
*/
void init_chaine_cond() {
	init_shm();

	/* initialize the queue attributes */
	init_boite_au_lettres();

	// ---- pour le "temps réel" ---- 
	launch_threads();
}

/**
	* connecte la shm pour la simulation
*/
void init_shm() {
	int shm_fd;
	// Création et attachement de la mémoire partagée
	shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
	if (shm_fd == -1) {
		perror("Erreur shm_open");
		exit(1);
	}

	if (ftruncate(shm_fd, sizeof(shm_data)) == -1) {
		perror("Erreur ftruncate");
		exit(1);
	}

	g_shm = mmap(NULL, sizeof(shm_data), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
	if (g_shm == MAP_FAILED) {
		perror("Erreur mmap");
		exit(1);
	}

}

/**
	* crée les boites au lettres de la chaine de conditionnement
*/
void init_boite_au_lettres() {
	bal_carton = creer_mqueue(BAL_CARTONS_NAME, BAL_NB_MAX_MESSAGE_DEFAUT);
	bal_impression =  creer_mqueue(BAL_IMPRESSION_NAME, 10);
	bal_palettes = creer_mqueue(BAL_PALETTES_NAME, BAL_NB_MAX_MESSAGE_DEFAUT);
}
/**
	* lance les thread de la chaine de conditionnement
*/
void launch_threads() {
	int err;

	if((err = creer_thread_tr(&thread_mise_en_carton, mise_en_carton, NULL, PRIO_DEFAUT)) != 0) {
		perror("creer_thread_tr");
	}
	if((err = creer_thread_tr(&thread_impression, impression, NULL, PRIO_DEFAUT)) != 0) {
		perror("creer_thread_tr");
	}
	if((err = creer_thread_tr(&thread_mise_en_palette, mise_en_palette, NULL, PRIO_DEFAUT)) != 0) {
		perror("creer_thread_tr");
	}
	if((err = creer_thread_tr(&thread_stockage, stockage, NULL, PRIO_DEFAUT)) != 0) {
		perror("creer_thread_tr");
	}
	if((err = creer_thread_tr(&thread_retrait, retrait, NULL, PRIO_DEFAUT)) != 0) {
		perror("creer_thread_tr");
	}
}

/**
	* join tous les thread de la mise en carton
*/
void join_all_threads() {
	pthread_join(thread_mise_en_carton, NULL);
	pthread_join(thread_impression, NULL);
	pthread_join(thread_mise_en_palette, NULL);
	pthread_join(thread_stockage, NULL);
	pthread_join(thread_retrait, NULL);

}

/**
	* detruit les boites au lettres de la chaine de conditionnement
*/
int destr_boite_au_lettres() {
	int err;
	if((err = mq_close(bal_carton))!=0 ) {
		// debug
		perror("Close bal carton");
		return err;
	}
	mq_unlink(BAL_CARTONS_NAME);
	if((err = mq_close(bal_impression))!=0 ) {
		// debug
		perror("Close bal impression");
		return err;
	}
	mq_unlink(BAL_IMPRESSION_NAME);
	if((err = mq_close(bal_palettes))!=0 ) {
		// debug
		perror("Close bal palettes");
		return err;
	}
	mq_unlink(BAL_PALETTES_NAME);
	return 0;
}

/**
	* unlink la shm entre la chaine de conditionnement et la simulation
*/
int destr_shm() {
	return shm_unlink(SHM_NAME);
}

/**
	détruit les boites au lettres et la shm de la chaine de conditionnement
*/
int detruire_objets_chaine_cond() {
	int err;
	// TODO retourner err si err !=0 ?
    err = destr_boite_au_lettres();

    err = destr_shm();

    return err;
}

/**
	* set des valeurs pour les variables globales pour les tests de mise_en_carton
*/
void set_test_values() {
	g_dim_a = 200;
	g_nb_pal_a = 3;
	g_nb_piec_cart_a = 5;
	g_nb_cart_pal_a = 8;
	g_seuil_defect_a = 10 * 10000;
	
	g_dim_b = 100;
	g_nb_pal_b = 2;
	g_nb_piec_cart_b = 4;
	g_nb_cart_pal_b = 5;
	g_seuil_defect_b = 10 * 10000;
}

